package jt.classic.system.workflow;

import jt.classic.system.ISystem;
import jt.classic.system.SimpleManager;
import jt.classic.system.group.IGroup;
import jt.classic.system.user.IUser;
import jt.classic.system.utils.AnnexTool;
import jt.classic.system.workflow.impl.WActivityImpl;
import jt.classic.system.workflow.impl.WExecutorImpl;
import jt.classic.system.workflow.impl.WInstanceImpl;
import jt.classic.system.workflow.impl.WNumberImpl;

import org.limp.basework.Column;
import org.limp.basework.ColumnNotFoundException;
import org.limp.basework.Table;
import org.limp.basework.analyzer.TableRegisterCenter;

import org.limp.mine.DataTrimmerI;
import org.limp.mine.annex.AnnexInfo;
import org.limp.mine.annex.transactor.AnnexTransactorException;

import java.sql.Connection;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 流程实例管理器
 *
 * @author bizkit
 *
 */
public class WInstanceManager extends SimpleManager {
    public WInstanceManager(Connection conn) {
        super(conn);
    }

    /**
     * 是否存在该流程的运行实例
     * @param flowid 流程ID
     * @return boolean
     */
    public boolean exitInstanceByFlowID(String flowid) {
        String sql = "SELECT INS_ID FROM WF_INSTANCE WHERE CG_ID = " + flowid;

        return this.trimmer.haveMoreData(sql);
    }

    /**
     * 是否存在该流程的运行实例
     * @param stepid 环节ID
     * @return
     */
    public boolean exitInstanceByStepID(String stepid) {
        String sql = "SELECT INS_ID FROM WF_ACTIVITY WHERE S_ID = " + stepid;

        return this.trimmer.haveMoreData(sql);
    }

    /**
     * 根据实例ID得到流程实例
     * @param id 实例ID
     * @return WInstance
     */
    public WInstance getInstanceByID(String id) throws WorkflowException {
        WInstance ins = null;
        String sql =
            "SELECT * FROM WF_INSTANCE LEFT JOIN ISYS_POST ON WF_INSTANCE.INS_CPOSTID = ISYS_POST.PID WHERE INS_ID = " +
            id;

        Map info = this.trimmer.searchSingleData(sql);

        if (info != null) {
            ins = new WInstanceImpl();

            String gid = (String) info.get("CG_ID");

            WorkflowManager manager = new WorkflowManager(this.conn);
            WFlow flow = manager.getWFlowById(gid);

            info.put("WFLOW", flow);

            WSupport support = flow.iobject().isupport();
            WSupportUGCenter supportCenter = null;

            try {
                supportCenter = support.iusergroupcenter();

                String creatorid = (String) info.get("INS_CREATORID");
                IUser creator = null;

                supportCenter.setConnection(this.conn);
                creator = supportCenter.getUserById(creatorid);

                String unitid = (String) info.get("INS_CUNITID");
                IGroup unit = null;

                supportCenter.setConnection(this.conn);
                unit = supportCenter.getGroupById(unitid);

                info.put("INS_CREATOR", creator);
                info.put("INS_CUNIT", unit);
            } catch (Exception ex) {
                ISystem.catchException(this, ex);
            } finally {
                if ((supportCenter != null) &&
                        !supportCenter.datasourceIsDefault()) {
                    supportCenter.clean();
                }
            }

            sql = "SELECT A_ID FROM WF_ACTIVITY WHERE INS_ID = " + id +
                " ORDER BY A_ID ASC";

            List list = this.trimmer.searchMultiData(sql);

            for (int i = 0; i < list.size(); i++) {
                String aid = (String) ((Map) list.get(i)).get("A_ID");
                WActivity activity = this.getActivityByID(aid, ins, flow);
                list.set(i, activity);
            }

            info.put("ACTIVITYLIST", list);

            AnnexTool tool = new AnnexTool(conn);

            String sequence = (String) info.get("INS_SEQUENCE");

            AnnexInfo[] temp = tool.getAnnexs(sequence, "WF_INSTANCE");

            if ((temp != null) && (temp.length > 0)) {
                info.put("DOC", temp[0]);
            }

            sql = "SELECT * FROM WF_NUMBER WHERE INS_SEQUENCE = '" + sequence +
                "' AND ONUSE = 1";

            Map numberinfo = this.trimmer.searchSingleData(sql);

            if (numberinfo != null) {
                sql = "SELECT * FROM WF_NUMBER_TYPE";

                Map m = this.trimmer.searchSymmetricalData(sql, "PKID",
                        "NUMBER_NAME");

                numberinfo.put("NUMBERMAP", m);
                numberinfo.put("OBJKEY", flow.iobject().ikey());

                WNumber num = new WNumberImpl();
                num.reload(numberinfo);

                info.put("NUMBER", num);
            }

            ins.reload(info);
        }

        return ins;
    }

    /**
     * 根据活动记录ID得到活动记录
     *
     * @param id 活动记录ID
     * @return WInstance
     */
    public WActivity getActivityByID(String id) throws WorkflowException {
        WActivity activity = null;

        String sql = "SELECT INS_ID FROM WF_ACTIVITY WHERE A_ID = ?";

        DataTrimmerI.DataItemList dil = this.trimmerI.createDIL();

        dil.set(id);

        Map info = this.trimmerI.searchSingleData(sql, dil);

        if (info != null) {
            String insid = (String) info.get("INS_ID");

            WInstance ins = this.getInstanceByID(insid);

            activity = ins.iactivity(id);
        }

        return activity;
    }

    /**
     * 根据活动记录ID得到活动记录
     *
     * @param id 活动记录ID
     * @return WInstance
     */
    private WActivity getActivityByID(String id, WInstance ins, WFlow flow)
        throws WorkflowException {
        WActivity activity = null;

        String sql = "SELECT * FROM WF_ACTIVITY WHERE A_ID = " + id;

        Map info = this.trimmer.searchSingleData(sql);

        if (info != null) {
            activity = new WActivityImpl();

            info.put("INSTANCE", ins);

            String lastid = (String) info.get("A_LASTID");

            String lockerid = (String) info.get("A_LOCKID");

            IUser locker = null;

            WSupport support = flow.iobject().isupport();

            WSupportUGCenter supportCenter = null;

            try {
                supportCenter = support.iusergroupcenter();

                supportCenter.setConnection(this.conn);

                if (!lockerid.equals("")) {
                    locker = supportCenter.getUserById(lockerid);

                    info.put("LOCKER", locker);
                }

                WExecutor executor = this.getExecutorByActivityID(id,
                        supportCenter);

                info.put("EXECUTOR", executor);
            } catch (Exception ex) {
                throw new WorkflowException("get activity[" + id + "] error.",
                    ex);
            } finally {
                if ((supportCenter != null) &&
                        !supportCenter.datasourceIsDefault()) {
                    supportCenter.clean();
                }
            }

            Map contents = this.getActivityContent(id);

            info.put("CONTENTS", contents);

            activity.reload(info);
        }

        return activity;
    }

    /**
     * 得到流程办理人实例
     * @param id
     * @return
     */
    private WExecutor getExecutorByActivityID(String aid,
        WSupportUGCenter supportCenter) throws WorkflowException {
        String sql = "SELECT * FROM WF_EXECUTOR WHERE A_ID = " + aid;
        WExecutor executor = null;
        Map info = this.trimmer.searchSingleData(sql);

        if (info != null) {
            executor = new WExecutorImpl();

            String uid = (String) info.get("USER_ID");

            IUser user = null;

            try {
                supportCenter.setConnection(this.conn);
                user = supportCenter.getUserById(uid);
            } catch (Exception ex) {
                throw new WorkflowException("get executor by activity[" + aid +
                    "] error.", ex);
            }

            String gid = (String) info.get("UNIT_ID");

            IGroup group = null;

            try {
                supportCenter.setConnection(this.conn);
                group = supportCenter.getGroupById(gid);
            } catch (Exception ex) {
                throw new WorkflowException("get executor unit by activity[" +
                    aid + "] error.", ex);
            }

            info.put("USER", user);
            info.put("GROUP", group);

            executor.reload(info);
        }

        return executor;
    }

    /**
     * 得到流程记录相关内容
     * @param aid 流程记录ID
     * @return Map
     */
    public Map getActivityContent(String aid) {
        String sql = "SELECT * FROM WF_ACTIVITY_OBJ WHERE A_ID = " + aid;

        List list = this.trimmer.searchMultiData(sql);

        Map result = null;

        if (!list.isEmpty()) {
            result = new HashMap();

            TableRegisterCenter center = TableRegisterCenter.getInstance();

            for (int i = 0; i < list.size(); i++) {
                Map temp = (Map) list.get(i);
                String tname = (String) temp.get("TABLENAME");
                String tkvalue = (String) temp.get("KEYVALUE");

                Table table = center.findTable(tname);

                if (table.hasPrimaryKey()) {
                    Column column = null;

                    try {
                        column = table.column(table.getPrimaryKey()[0]);
                    } catch (Exception ex) {
                        ISystem.catchException(this, ex);
                    }

                    if (column.getType().toString().equals("varchar")) {
                        sql = "SELECT * FROM " + tname + " WHERE " +
                            column.getName() + " = " + tkvalue;
                    } else {
                        sql = "SELECT * FROM " + tname + " WHERE " +
                            column.getName() + " = '" + tkvalue + "'";
                    }

                    Map content = this.trimmer.searchSingleData(sql);

                    if (content != null) {
                        if (table.hasAnnex()) {
                            String[] annexs = table.getAnnex();

                            if (annexs != null) {
                                AnnexTool tool = new AnnexTool(this.conn);

                                for (int j = 0; j < annexs.length; j++) {
                                    String ax = annexs[j];

                                    try {
                                        Column annexColumn = table.column(ax);

                                        if ("ALLFREE".equals(
                                                    annexColumn.getFormName()
                                                                   .toUpperCase()) ||
                                                "ALLRESTRICT".equals(
                                                    annexColumn.getFormName()
                                                                   .toUpperCase())) {
                                            AnnexInfo[] annexinfos = tool.getAnnexs(tkvalue,
                                                    table.getName());

                                            if ((annexinfos != null) &&
                                                    (annexinfos.length > 0)) {
                                                content.put(ax, annexinfos);
                                            }
                                        } else {
                                            AnnexInfo annex = tool.getAnnex(tkvalue,
                                                    table.getName(),
                                                    annexColumn.getFormName());

                                            if (annex != null) {
                                                content.put(ax, annex);
                                            }
                                        }
                                    } catch (Exception ex) {
                                        ISystem.catchException(this, ex);
                                    }
                                }
                            }
                        }

                        if (result.containsKey(tname)) {
                            ((List) result.get(tname)).add(content);
                        } else {
                            List l = new ArrayList();
                            l.add(content);
                            result.put(tname, l);
                        }
                    } else {
                        ISystem.catchException(new WorkflowException(
                                "Workflow Activity['" + aid +
                                "'] Content is Null -> [" + sql + "]"));
                    }
                }
            }
        }

        return result;
    }

    /**
     * 实例归档
     *
     * @param insid 实例ID
     * @param user 操作用户
     * @exception WorkflowException
     */
    public void pigeonholeInstance(String insid, IUser user)
        throws WorkflowException {
        String sql = "UPDATE WF_INSTANCE SET INS_STATE = 2 WHERE INS_ID = ?";

        DataTrimmerI.DataItemList dil = this.trimmerI.createDIL();

        dil.set(insid);

        if (!this.trimmerI.execute(sql, dil)) {
            throw new WorkflowException("pigeonhole workflow instance error.");
        }
    }

    /**
     * 删除实例
     *
     * @param insid 实例ID
     * @param user 操作用户
     * @exception WorkflowException
     */
    public void deleteInstance(String insid, IUser user)
        throws WorkflowException {
        WInstance instance = this.getInstanceByID(insid);

        List actList = instance.iactivitylist();

        for (int j = 0; j < actList.size(); j++) {
            WActivity act = (WActivity) actList.get(j);

            this.deleteActivity(act, user);
        }

        String sql = "DELETE FROM WF_INSTANCE WHERE INS_ID = ?";

        DataTrimmerI.DataItemList dil = this.trimmerI.createDIL();

        dil.set(insid);

        if (!this.trimmerI.execute(sql, dil)) {
            throw new WorkflowException("delete workflow instance error.");
        }

        AnnexTool tool = new AnnexTool(conn);

        try {
            tool.deleteAnnex(instance.isequence(), "WF_INSTANCE");
        } catch (AnnexTransactorException ex) {
            throw new WorkflowException("delete workflow instance error.", ex);
        }
    }

    /**
     * 删除实例活动记录
     * @param actid 活动记录ID
     * @param user 操作用户
     * @throws WorkflowException
     */
    private void deleteActivity(WActivity activity, IUser user)
        throws WorkflowException {
        StringBuffer sqlString = new StringBuffer();

        sqlString.append(";");
        sqlString.append("DELETE FROM WF_ACTIVITY WHERE A_ID = " +
            activity.id());
        sqlString.append(";");
        sqlString.append("DELETE FROM WF_EXECUTOR WHERE A_ID = " +
            activity.id());
        sqlString.append(";");
        sqlString.append("DELETE FROM WF_ACTIVITY_OBJ WHERE A_ID = " +
            activity.id());

        if (!this.trimmer.executeBatch(sqlString.toString())) {
            throw new WorkflowException("delete activity error.");
        }

        WObject obj = activity.instance().iflow().iobject();
        List list = obj.itables();

        if ((list != null) && !list.isEmpty()) {
            AnnexTool tool = new AnnexTool(conn);

            for (int i = 0; i < list.size(); i++) {
                Table table = (Table) list.get(i);

                if (table.hasPrimaryKey()) {
                    Column keycolumn = null;

                    try {
                        keycolumn = table.column(table.getPrimaryKey()[0]);
                    } catch (ColumnNotFoundException ex) {
                        throw new WorkflowException("delete activity error.", ex);
                    }

                    List contents = activity.icontent(table);

                    String sql = null;

                    if ((contents != null) && !contents.isEmpty()) {
                        for (int j = 0; j < contents.size(); j++) {
                            Map temp = (Map) contents.get(j);
                            String keyvalue = (String) temp.get(keycolumn.getName());

                            sql = "DELETE FROM " + table.getName() + " WHERE " +
                                keycolumn.getName() + " = ?";

                            DataTrimmerI.DataItemList dil = this.trimmerI.createDIL();

                            dil.set(keyvalue);

                            if (this.trimmerI.execute(sql, dil)) {
                                try {
                                    tool.deleteAnnex(keyvalue, table.getName());
                                } catch (AnnexTransactorException ex) {
                                    throw new WorkflowException("delete activity error.",
                                        ex);
                                }
                            } else {
                                throw new WorkflowException(
                                    "delete activity error.");
                            }
                        }
                    }
                }
            }
        }
    }
}
